using System;
using System.Collections.Generic;
using System.IO;
using UnityEngine;

namespace RedPoint.Runtime {
    
    public class PointNode
    {
        // 节点的名称（仅表示该节点的名称）
        private string m_Name;
        // 完整的路径
        private string m_FullPath;
        
        // 父节点
        public PointNode Parent { get; private set; }
        // 子节点列表（子节点名称，子节点引用）
        private Dictionary<string, PointNode> m_Childrens;

        
        // 变换时回调
        private Action<int> m_ChangeCallback;
        // 节点的值
        public int Value { get; private set; }
        
        public string Name
        {
            get { return m_Name; }
        }
        
        // 完整路径
        public string FullPath
        {
            get
            {
                if (string.IsNullOrWhiteSpace(m_FullPath))
                {
                    if (Parent == null || Parent == RedPointManager.Instance.Root)
                    {
                        m_FullPath = m_Name;
                    }
                    else
                    {
                        m_FullPath = Parent.Name + RedPointManager.CharSplit + m_Name;

                    }
                }

                return m_FullPath;
                
            }
        }

        // 子节点数量
        public int ChildrenCount
        {
            get
            {
                if (m_Childrens == null)
                {
                    return 0;
                }
                
                int sum = m_Childrens.Count;
                foreach (var child in m_Childrens.Values)
                {
                    sum += child.ChildrenCount;
                }
                return sum;
            }
        }
        
        // 子节点列表
        public Dictionary<string, PointNode>.ValueCollection Childrens
        {
            get
            {
                return m_Childrens?.Values;
            }
        }

        /// <summary>
        /// 添加节点改变时回调
        /// </summary>
        /// <param name="callback"></param>
        public void AddListenerChangeCallback(Action<int> callback)
        {
            m_ChangeCallback += callback;
        }

        /// <summary>
        /// 移除节点改变时回调
        /// </summary>
        /// <param name="callback"></param>
        public void RemoveListenerChangeCallback(Action<int> callback)
        {
            m_ChangeCallback -= callback;
        }

        /// <summary>
        /// 清空回调
        /// </summary>
        public void RemoveAllListenersChangeCallback()
        {
            m_ChangeCallback = null;
        }

        /// <summary>
        /// 改变节点的值【只能在叶子节点上调用】
        /// </summary>
        /// <param name="newValue"></param>
        public void ChangeValue(int newValue)
        {
            if (m_Childrens != null && m_Childrens.Count != 0)
            {
                Debug.LogWarning("不允许之间修改【非叶子节点】的值，Node : " + FullPath);
                return;
            }
            
            InternalChangeValue(newValue);
        }

        /// <summary>
        /// 改变节点的值【只对非叶子节点有效】
        /// </summary>
        public void ChangeValue()
        {
            if (m_Childrens == null || m_Childrens.Count == 0)
            {
                return;
            }

            // 计算所以子节点总值
            int sum = 0;
            foreach (var child in m_Childrens.Values)
            {
                sum += child.Value;
            }
            
            InternalChangeValue(sum);
        }

        /// <summary>
        /// 改变节点值
        /// </summary>
        /// <param name="newValue"></param>
        private void InternalChangeValue(int newValue)
        {
            if (Value == newValue)
            {
                return;
            }
            
            Value = newValue;
            m_ChangeCallback?.Invoke(Value);
            
            // 值改变时回调
            RedPointManager.Instance.NodeValueChangeCallback?.Invoke(this, newValue);
            
            // 标记父节点为脏节点
            RedPointManager.Instance.MarkDirtyNode(Parent);
        }

        /// <summary>
        /// 获取节点
        /// </summary>
        /// <param name="key">节点路径</param>
        /// <returns>返回节点</returns>
        public PointNode GetChild(string key)
        {
            if (m_Childrens == null || m_Childrens.Count == 0) return null;

            m_Childrens.TryGetValue(key, out PointNode child);
            return child;
        }

        /// <summary>
        /// 获取子节点并且不存在时添加新节点
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public PointNode GetOrAddChild(string key)
        {
            PointNode child = GetChild(key);

            if (child == null)
            {
                child = AddChild(key);
            }
            
            return child;
        }
        
        /// <summary>
        /// 添加子节点
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public PointNode AddChild(string key)
        {
            if (m_Childrens == null)
            {
                m_Childrens = new Dictionary<string, PointNode>();
            }

            if (m_Childrens.ContainsKey(key))
            {
                Debug.LogError(string.Format("节点{0}已经存在，无法重复添加{1}", key, Name));
                return null;
            }
            
            PointNode child = new PointNode(key, this);
            m_Childrens.Add(key, child);
            
            // 节点数量改变时回调
            RedPointManager.Instance.NodeNumChangeCallback?.Invoke();
            
            return child;
        }
        
        /// <summary>
        /// 移除子节点
        /// </summary>
        /// <param name="key">子节点名称</param>
        public bool RemoveChild(string key)
        {
            if (m_Childrens == null || m_Childrens.Count == 0)
            {
                return false;
            }

            PointNode child = GetChild(key);

            if (child != null)
            {
                m_Childrens.Remove(key);
                
                // 父节点标记为脏节点
                RedPointManager.Instance.MarkDirtyNode(Parent);
                
                // 窗口更新
                RedPointManager.Instance.NodeNumChangeCallback?.Invoke();

                return true;
            }

            return false;
        }
        
        /// <summary>
        /// 移除所有子节点
        /// </summary>
        public void RemoveAllChild()
        {
            if (m_Childrens == null || m_Childrens.Count == 0)
            {
                return;
            }

            m_Childrens.Clear();
            RedPointManager.Instance.MarkDirtyNode(this);
            RedPointManager.Instance.NodeNumChangeCallback?.Invoke();
        }

        public PointNode(string name)
        {
            m_Name = name;
            Value = 0;
            m_ChangeCallback = null;
        }

        public PointNode(string name, PointNode parent) : this(name)
        {
            Parent = parent;
        }

        public override string ToString()
        {
            return FullPath;
        }
    }
    
}

